#pragma once

#include "Common.h"
#include "Log.h"
#include "Epoll.h"
#include <memory>
#include "Connection.h"
#include <unordered_map>

namespace zmh
{
    class Reactor
    {
        const static int MAXEVENTS = 128; // 一次可拷贝到用户空间就绪事件个数
    public:
        void AddConnection(std::unique_ptr<zmh::Connection> conn)
        {
            int fd = conn->GetFd();
            if (_connections.count(fd) == 0)
            {
                // 1. 设置连接的管理者
                conn->SetOwner(this);

                // 2. 渗透到内核
                _epoller->AddEvent(fd, conn->Events());

                // 3. 交由_connections对象进行管理
                _connections[fd] = std::move(conn);
            }
        }
        void ModConnection(int fd, uint32_t event)
        {
            if (_connections.count(fd) == 1)
            {
                // 1. 渗透到内核
                _epoller->ModEvent(fd, event);

                // 2. 对_connections[fd]事件重新设计
                _connections[fd]->SetEvents(event);
            }
        }
        void DelConnection(int fd)
        {
            if (_connections.count(fd) == 1)
            {
                // 1. 渗透到内核
                _epoller->DelEvent(fd);

                // 2. 移除对_connections[fd]的管理
                _connections.erase(fd);

                // 3. 关闭文件描述符
                close(fd);
            }
        }
        void Loop()
        {
            // 至少要存在一个监听连接
            if (_connections.empty() == true)
                return;
            while (true)
            {
                int n = _epoller->Wait(_events, MAXEVENTS);
                if (n <= 0) // 错误、无事件！！！
                    break;
                for (int i = 0; i < n; i++)
                {
                    int fd = _events[i].data.fd;
                    uint32_t event = _events[i].events;
                    if (_connections.count(fd) == 0)
                    {
                        LOG(LogLevel::ERROR) << "fd not exist,fd: " << fd;
                        continue;
                    }
                    if (event & EPOLLERR) // 将fd的错误异常转换为IO错误
                        event |= EPOLLIN | EPOLLOUT;
                    if (event & EPOLLHUP) // 将fd的错误异常转换为IO错误
                        event |= EPOLLIN | EPOLLOUT;
                    if (event & EPOLLIN)
                        _connections[fd]->Recv();
                    if (event & EPOLLOUT)
                        _connections[fd]->Send();
                }
            }
        }

    private:
        // 1. 创建一个Epoll模型
        std::unique_ptr<Epoll> _epoller = std::make_unique<Epoll>();
        // 2. 对所有连接(包括监听套接字)Connection进行管理
        std::unordered_map<int, std::unique_ptr<zmh::Connection>> _connections;
        // 3. 由内核返回的就绪的事件
        struct epoll_event _events[MAXEVENTS];
    };
};